#include <pit/pitd.h>
#include <board.h>
#include <cp15/cp15.h>
#include <memories/MEDSdcard.h>
#include <ff.h>
#include <d264.h>
#include <clock.h>

////////////////////////////////////////////////////////////////////////////////
// CACHE

#if defined (AT91C_IRAM_1)
#define SRAM_ADDRESS  AT91C_IRAM_1
#define SRAM_SIZE     AT91C_IRAM_1_SIZE
#elif defined(AT91C_IRAM)
#define SRAM_ADDRESS  AT91C_IRAM
#define SRAM_SIZE     AT91C_IRAM_SIZE
#elif defined(AT91C_ISRAM)
#define SRAM_ADDRESS  AT91C_ISRAM
#define SRAM_SIZE     AT91C_ISRAM_SIZE
#else
#error SRAM define
#endif

#define SDRAM_ADDRESS 0x20000000

unsigned int pTranslationTable[4*1024] __attribute__((section(".trans")));

static void InitMMU()
{
    int i;

    extern int _snocache;
    extern int _enocache;

    // Program the TTB
    _writeTTB((unsigned int) pTranslationTable);

    // Program the domain access register
    _writeDomain(0xC0000000); // domain 15: access are not checked

    // Program level 1 page table entry
    // Vector adress
    for (i = 0; i < 0xB; ++i)
        pTranslationTable[i] = (i << 20) | // Physical Address
                (1 << 10) | // Access in supervisor mode
                (15 << 5) | // Domain
                (1 << 4) | (0 << 3) | // No D cache
                0x2; // Set as 1 Mbyte section

    // Reset table entries
    for (; i < (SRAM_ADDRESS >> 20); ++i)
        pTranslationTable[i] = 0;

    // SRAM adress (with D cache)
    pTranslationTable[SRAM_ADDRESS >> 20] = (SRAM_ADDRESS) | // Physical Address
                    (1 << 10) | // Access in supervisor mode
                    (15 << 5) | // Domain
                    (1 << 4) | (1 << 3) | // D cache
                    0x2; // Set as 1 Mbyte section

    // Reset table entries
    for (++i; i < (SDRAM_ADDRESS >> 20); ++i)
        pTranslationTable[i] = 0;

    // SDRAM adress (with D cache)
    for (; i < (((int)&_snocache) >> 20); ++i)
        pTranslationTable[i] = (i << 20) | // Physical Address
                (1 << 10) | // Access in supervisor mode
                (15 << 5) | // Domain
                (1 << 4) | (1 << 3) | // D cache
                0x2; // Set as 1 Mbyte section

    // SDRAM adress (without D cache)
    for (; i < (((int)&_enocache) >> 20); ++i)
        pTranslationTable[i] = (i << 20) | // Physical Address
                (1 << 10) | // Access in supervisor mode
                (15 << 5) | // Domain
                (1 << 4) | (0 << 3) | // No D cache
                0x2; // Set as 1 Mbyte section

    // SDRAM adress (with D cache)
    for (; i < (SDRAM_ADDRESS >> 20) + 64; ++i)
        pTranslationTable[i] = (i << 20) | // Physical Address
                (1 << 10) | // Access in supervisor mode
                (15 << 5) | // Domain
                (1 << 4) | (1 << 3) | // D cache
                0x2; // Set as 1 Mbyte section

    // Reset table entries
    for (; i < 0xFFF; ++i)
        pTranslationTable[i] = 0;

    // Peripherals adress
    pTranslationTable[0xFFF] = (0xFFF00000) | // Physical Address
            (1 << 10) | // Access in supervisor mode
            (15 << 5) | // Domain
            (1 << 4) | (0 << 3) | // No D cache
            0x2; // Set as 1 Mbyte section
}

////////////////////////////////////////////////////////////////////////////////
// TEST

#define INTERRUPT_PERIOD 1e3 // microsseconds

//static char *filename = "0:videos/suzie.264";
static char *filename = "0:videos/507K382/carphone.264";

volatile static unsigned long long elapsed;

Media sdcard;

static void dummy_write()
{
}

static void timer(void)
{
    ++elapsed;
}

int main(void)
{
    int iRet, iFramesDecoded = 0;
    DecodedPicList *pDecPicList;
    InputParameters *pInputParams = &cfgparams;
    FATFS fs = { 0 };

    CLOCK_SetConfig(1);

    InitMMU();
    CP15_EnableMMU();
    CP15_Enable_D_Cache();
    CP15_Enable_I_Cache();

    MEDSdcard_Initialize(&sdcard, 1);

    f_mount(DRV_MMC, &fs);
    f_chdrive(DRV_MMC);
    f_chdir("0:");

    //get input parameters;
    Configure(filename, NULL, dummy_write);

    //open decoder;
    iRet = OpenDecoder(pInputParams);
    if (iRet != DEC_OPEN_NOERR) {
        return -1; //failed;
    }

    PITD_Configure(timer, INTERRUPT_PERIOD, 1);
    PITD_Start();

    //decoding;
    do {
        iRet = DecodeOneFrame(&pDecPicList);
        if (iRet == DEC_EOS || iRet == DEC_SUCCEED) {
            //process the decoded picture, output or display;
            iFramesDecoded++;
        } else {
            //error handling;
            return -1;
        }
    } while ((iRet == DEC_SUCCEED) && ((cfgparams.iDecFrmNum == 0)
            || (iFramesDecoded < cfgparams.iDecFrmNum)));

    PITD_Stop();

    iRet = FinitDecoder(&pDecPicList);
    iRet = CloseDecoder();

    CP15_Disable_I_Cache();
    CP15_Disable_D_Cache();
    CP15_DisableMMU();

    return 0;
}
